我們要接續昨天的進度,為首頁新增一個功能,提示即將到期的物品,讓使用者能一眼就看見哪些物品需要注意,避免過期浪費。這個功能將顯示在首頁物品列表的上方,並會根據當前選擇的月份來顯示即將到期的物品。
ExpiringItemsView 為負責顯示即將到期物品的區塊,它會根據當前月份即將到期的物品列表進行顯示。如果有到期的物品,列表會顯示物品的名稱及到期日;如果沒有,即顯示一條提示文字告知沒有即將到期的物品。
struct ExpiringItemsView: View {
@ObservedObject var viewModel: ItemViewModel
var body: some View {
if viewModel.expiringItems.isEmpty {
// 如果沒有即將到期的物品,顯示一個簡單的提示
Text("本月沒有即將到期的物品")
.font(.subheadline)
.foregroundColor(.gray)
.padding(.top, 10)
} else {
ScrollView {
LazyVStack(spacing: 15) {
ForEach(viewModel.expiringItems, id: \.id) { item in
HStack(spacing: 15) {
Image(systemName: "clock.fill")
.foregroundColor(daysUntilExpiry(item.expiryDate) <= 3 ? .red : .yellow)
.font(.title2)
VStack(alignment: .leading, spacing: 5) {
Text(item.name)
.font(.headline)
.foregroundColor(.primary)
Text("到期日: \(item.expiryDate?.formatted(date: .abbreviated, time: .omitted) ?? "未設定")")
.font(.subheadline)
.foregroundColor(.secondary)
}
Spacer()
Text(item.location.name)
.font(.subheadline)
.padding(6)
.background(Color.blue.opacity(0.2))
.foregroundColor(.blue)
.cornerRadius(5)
}
.padding()
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(10)
.shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2)
}
}
.padding(.horizontal)
}
}
}
}
而列表不止顯示物品的名稱、到期日和放置地點,還會根據物品的到期日做出不同的顏色提示:三天內到期的物品會顯示紅色圖標,其他物品則會顯示黃色圖標,讓使用者可以一目了然地知道哪些物品需要優先處理。
func daysUntilExpiry(_ expiryDate: Date?) -> Int {
guard let expiryDate = expiryDate else { return Int.max }
let currentDate = Date()
let diffComponents = Calendar.current.dateComponents([.day], from: currentDate, to: expiryDate)
return diffComponents.day ?? Int.max
}
接著,我們需要在 HomeViewModel 中實作一個屬性 expiringItems,該屬性篩選出所有尚未使用完畢且到期日在當前月份內的物品。
var expiringItems: [Item] {
let calendar = Calendar.current
return items.filter { item in
if let expiryDate = item.expiryDate {
let itemMonth = calendar.component(.month, from: expiryDate)
let itemYear = calendar.component(.year, from: expiryDate)
let selectedMonth = calendar.component(.month, from: selectedDate)
let selectedYear = calendar.component(.year, from: selectedDate)
return itemMonth == selectedMonth && itemYear == selectedYear && !(item.isUsedUp)
}
return false
}
}
這裡的 expiringItems 會根據選定的月份篩選即將到期的物品。通過 Calendar 的 .component 方法來比對物品到期日與選擇的月份,從而只顯示當前月份到期的物品。
參考資料:
最後,我們需要將 ExpiringItemsView 整合到 HomeView 中,讓它顯示在物品列表的上方。只要 HomeView 的物品資訊發生變化,提示區塊也會根據篩選後的資料自動更新。
struct HomeView: View {
// 略...
var body: some View {
NavigationView {
ZStack(alignment: .bottomTrailing) {
VStack {
ExpiringItemsView(viewModel: viewModel)
.frame(height:250)
ItemListView(viewModel: viewModel)
.frame(maxHeight: .infinity)
.frame(maxWidth: .infinity)
.onAppear {
viewModel.fetchItems()
}
}
// 略...
今天我們成功在首頁的物品列表上方新增了即將到期物品的提示區塊,並根據到期日提供不同的顏色提示。這個功能幫助使用者更好地管理物品的有效期,避免過期浪費。